React - Componenten
Home

React - Componenten

React - Componenten

Bijna alles in React bestaat uit componenten, en die kunnen klassecomponenten of eenvoudige componenten zijn. De meeste React-apps hebben veel kleine componenten en alles wordt in de hoofdcomponent van de app geladen. Componenten staan meestal een eigen bestand.

React gaat uit van de vaststelling dat de logica om informatie weer te geven (rendering) inherent gekoppeld aan andere UI-logica: hoe gebeurtenissen worden afgehandeld, hoe de status verandert in de tijd en hoe de gegevens worden voorbereid voor weergave.

In plaats van op kunstmatige wijze technologieën te scheiden door markup en logica in afzonderlijke bestanden op te slaan, maakt React een onderscheid tussen concerns (bedoelingen) door elke bedoeling in afzonderlijke, los gekoppelde, componenten onder te brengen.

We leren twee soorten componenten maken en we leggen de nadruk op encapsulatie en herbruikbaarheid ervan:

  1. functie-component
  2. klasse-component

Een component met props maken

De gebruikersinterface wordt opgesplitst in onafhankelijke, herbruikbare componenten die elk op zich één bepaalde verantwoordelijkheid hebben. Deze pagina geeft een inleiding op het idee van componenten. Hier maken we kennis met de fundamentele React concepten. Voor meer gedetailleerde informatie verwijzen we naar de component-API-referentie.

Conceptueel zijn componenten JavaScript-functies. Ze accepteren willekeurige invoer ("props" genoemd) en geven React-elementen terug die beschrijven wat er op het scherm moet verschijnen.

  1. Functie-componenten
    1. Het schrijven van een functie is de gemakkelijkste manier om een component te definiëren. We nemen het Marvel voorbeeld uit React - Knooppunten en breken de code op in componenten. We maken een functie-component die de taak op zich neemt om 1 Marvelpersonnage op een tegel te tonen:
      function MarvelCharacter(props) {
          return (<div style={marvelCharacterStyle.tile}>
              {props.name}
              <img src={props.imageUrl}
                  style={marvelCharacterStyle.image} alt={"foto van " + props.name} />
          </div>);
      }
      
    2. We gebruiken de kennis die we hebben over objecten in JavaScript om de CSS stijlregels te groeperen in 1 stijlknoopunt:
      const marvelCharacterStyle = {
          list: {
              color: 'green',
              display: 'flex',
              flexWrap: 'wrap'
          },
          tile: {
              color: 'white',
              backgroundColor: 'red',
              textAlign: 'center',
              width: '10em',
              fontSize: '2em',
              fontFamily: 'Arial',
              paddingTop: '0.5em'
          },
          image: {
              color: 'blue',
              width: '10em',
              paddingTop: '0.5em'
          }
      };
    3. We passen ons marvel knooppunt aan en gebruiken JSX om met een zelfgemaakte tag met de naam MarvelCharacter de functie-component te laten uitvoeren. We geven twee attributen mee, die door JSX zullen worden omgezet naar een JS object en als argument aan de functie-component worden doorgegeven:

      const marvel = (
          <div>
              <h1>Marvel Personnages</h1>
              <div style={marvelCharacterStyle}>
                  <MarvelCharacter name="Avengers"
                      imageUrl="http://i.annihil.us/u/prod/marvel/i/mg/0/03/523219b086a17.jpg" />
              </div>
          </div>
      );
    4. Nu moeten we nog de andere personnages toevoegen. We zouden nog 4 MarvelCharacter tags manueel kunnen toevoegen. Maar we gaan opnieuw onze kennis van JavaScript arrays en objecten gebruiken.
      1. Voor elke personnage maken we een object met de nodige kenmerken en die stoppen we in een array:
        // object met de gegevens van de Marvelpersonnages
        const MarvelCharacters = [
            {
                name: 'Avengers',
                imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/0/03/523219b086a17.jpg'
            },
            {
                name: 'Hulk',
                imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/5/a0/538615ca33ab0.jpg'
            },
            {
                name: 'Spider-Man',
                imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/3/50/526548a343e4b.jpg'
            },
            {
                name: 'Spider-Girl',
                imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/1/70/4c003adccbe4f.jpg'
            },
            {
                name: 'X-Man',
                imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/d/10/535febd73f84f.jpg'
            }
        ]
        
        
      2. om dan met de map methode voor elk element in de array een tegel te genereren:
        const marvel = (
            <div>
                <h1>Marvel Personnages</h1>
                <div style={marvelCharacterStyle.list}>
                    {MarvelCharacters.map(element => MarvelCharacter(element))}
                </div>
            </div>
        );
      3. De functie-component MarvelCharacter en het stijl-object marvelCharacterStyle blijven ongewijzigd. Hier volgt de volledige code tot nu toe van static-react/component.html:

        <!DOCTYPE html>
        <html lang="nl">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Snel starten met React</title>
            <!-- Note: when deploying, replace "development.js" with "production.min.js". -->
            <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
            <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
            <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
            <script type="text/babel">
                // object met de gegevens van de Marvelpersonnages
                const MarvelCharacters = [
                    {
                        name: 'Avengers',
                        imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/0/03/523219b086a17.jpg'
                    },
                    {
                        name: 'Hulk',
                        imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/5/a0/538615ca33ab0.jpg'
                    },
                    {
                        name: 'Spider-Man',
                        imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/3/50/526548a343e4b.jpg'
                    },
                    {
                        name: 'Spider-Girl',
                        imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/1/70/4c003adccbe4f.jpg'
                    },
                    {
                        name: 'X-Man',
                        imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/d/10/535febd73f84f.jpg'
                    }
                ]
                // we gaan veel keer createElement moeten gebruiken
                // we maken een afkorting
                const e = React.createElement;
                const marvelCharacterStyle = {
                    list: {
                        color: 'green',
                        display: 'flex',
                        flexWrap: 'wrap'
                    },
                    tile: {
                        color: 'white',
                        backgroundColor: 'red',
                        textAlign: 'center',
                        width: '10em',
                        fontSize: '2em',
                        fontFamily: 'Arial',
                        paddingTop: '0.5em'
                    },
                    image: {
                        color: 'blue',
                        width: '10em',
                        paddingTop: '0.5em'
                    }
                };
                function MarvelCharacter(props) {
                    return (<div style={marvelCharacterStyle.tile}>
                        {props.name}
                        <img src={props.imageUrl}
                            style={marvelCharacterStyle.image} alt={"foto van " + props.name} />
                    </div>);
                }
                const marvel = (
                    <div>
                        <h1>Marvel Personnages</h1>
                        <div style={marvelCharacterStyle.list}>
                            {MarvelCharacters.map(element => MarvelCharacter(element))}
                        </div>
                    </div>
                );
            </script>
        </head>
        <body>
            <div id="root"></div>
            <script type="text/babel">
                ReactDOM.render(marvel, document.querySelector('#root'))
            </script>
        </body>
        </html>
  2. Klassencomponenten
    1. We gaan nog een stap verder en willen alle functionaliteit van de Marvelpersonnages in 1 component onderbrengen (encapsuation) die we gemakkelijk op om het even welke webpagina kunnen plaatsen. Daarmee willen we het nut van componenten illustreren:
      1. 1 verantwoordelijkheid
      2. herbruikbaar
    2. Stappen:
      1. Maak een ES6-klasse met dezelfde naam die React.Component uitbreidt.
      2. Voeg er een enkele lege methode aan toe, genaamd render().
      3. Plaats de code die de reactknooppunten toont in de body van de render() methode.
      4. We verwijzen naar de eigenschappen en methoden van de klasse met het this keyword. Vervang bijvoorbeeld props door this.props in de render() body.
      5. Om de waarschuwing te vermijden dat er een key moet worden verstrekt voor lijstitems voegen we die als attribuut toe. Een 'key' is een unieke waarde die je moet opgeven bij het maken van lijsten met elementen. We voegen dus een key attribuut toe aan de div die één Marvelpersonnage bevat..

      6. De Marvel klassencomponent stoppen we in een apart bestand met de naam js/marvel.js:
        class Marvel extends React.Component {
            // we gaan veel keer createElement moeten gebruiken
            // we maken een afkorting
            e = React.createElement;
            marvelCharacterStyle = {
                list: {
                    color: 'green',
                    display: 'flex',
                    flexWrap: 'wrap'
                },
                tile: {
                    color: 'white',
                    backgroundColor: 'red',
                    textAlign: 'center',
                    width: '10em',
                    fontSize: '2em',
                    fontFamily: 'Arial',
                    paddingTop: '0.5em'
                },
                image: {
                    color: 'blue',
                    width: '10em',
                    paddingTop: '0.5em'
                }
            };
        
            MarvelCharacter(props) {
                return (<div style={this.marvelCharacterStyle.tile} key={props.name}>
                    {props.name}
                    <img src={props.imageUrl}
                        style={this.marvelCharacterStyle.image} alt={"foto van " + props.name} />
                </div>);
            }
        
            render() {
                return (
                    <div>
                        <h1>{this.props.heading}</h1>
                        <div style={this.marvelCharacterStyle.list}>
                            {this.props.list.map(element => this.MarvelCharacter(element))}
                        </div>
                    </div>
                );
            }
        }
      7. Nu we de component netjes afgeschermd in een bestand hebben staan kunnen die heel eenvoudig op een webpagina gebruiken. De moeite om de component wordt ruimschoots vergoed door het gemak waarmee we de component op een webpagina kunnen zetten. Het voorbeeld staat in static-react/class-component.html;
        <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Snel starten met React</title>
            <!-- Note: when deploying, replace "development.js" wi="textth "production.min.js". -->
            <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
            <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
            <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
            <script type="text/babel" src="js/marvel.js"></script>
            <script type="text/babel">
                // object met de gegevens van de Marvelpersonnages
                const MarvelCharacters = [
                    {
                        name: 'Avengers',
                        imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/0/03/523219b086a17.jpg'
                    },
                    {
                        name: 'Hulk',
                        imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/5/a0/538615ca33ab0.jpg'
                    },
                    {
                        name: 'Spider-Man',
                        imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/3/50/526548a343e4b.jpg'
                    },
                    {
                        name: 'Spider-Girl',
                        imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/1/70/4c003adccbe4f.jpg'
                    },
                    {
                        name: 'X-Man',
                        imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/d/10/535febd73f84f.jpg'
                    }
                ]
            </script>
        </head>
        <body>
            <div id="root"></div>
            <script type="text/babel">
                ReactDOM.render(<Marvel list = {MarvelCharacters} heading = "John's keuze"/>, document.querySelector('#root'))
            </script>
        </body>
        </html>
        1. We laden het js bestand waarin de Marvel component staat met type="text/babel".
        2. De data staat in een object met de naam MarvelCharacters en is extern aan de component. Dat is nodig omdat de Marvel component ook andere Marvel-personnages moet kunnen tonen.
        3. De titel geven we door als de waarde van het heading attribuut van het Marvel element en de data geven we mee als de waarde van het list attribuut. Achter de schermen worden die twee attributen en hun waarden in het props object van de Marvel component omgezet en doorgegeven.
        4. Aan de render methode van het ReactDOM object geven we het Marvel element door om op de pagina weergegeven te worden. Achter de schermen gaat JSX dat eigengemaakt <Marvel/> XML element vervangen door de klasse Marvel.
      8. We hebben net gezien dat zo'n op zichzelf bestaande component gemakkelijk te gebruiken is. Nu gaan tonen dat die ook gemakkelijk te hergebruiken is. We gaan de selectie van Farah tonen.
        1. We maken een object met de personnages die Farah gekozen heeft:
          const FarahChoiceMarvelCharacters = [
              {
                  name: 'Agent Brand',
                  imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/4/60/52695285d6e7e.jpg'
              },
              {
                  name: 'Anita Blake',
                  imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/2/a0/4c0038fa14452.jpg'
              },
              {
                  name: 'Butterfly',
                  imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/8/00/4c0030b5dbc50.jpg'
              },
              {
                  name: 'Spider-Girl',
                  imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/1/70/4c003adccbe4f.jpg'
              },
              {
                  name: 'Lyja',
                  imageUrl: 'http://i.annihil.us/u/prod/marvel/i/mg/3/40/4c003594c52e8.jpg'
              }
          ]
        2. We wijzigen de html in de body van static-react/class-component.html. We voegen in de #root div twee div's toe om respectievelijk de keuze van John en Farah te tonen. We roepen twee keer de render methode op ReactDom om de keuzes te renderen:
          <body>
              <div id="root">
                  <div id="john"></div>
                  <div id="farah"></div>
              </div>
              <script type="text/babel">
                  ReactDOM.render(<Marvel list={MarvelCharacters} heading="John's keuze" />, 
                      document.querySelector('#john'))
                  ReactDOM.render(<Marvel list={FarahChoiceMarvelCharacters} heading="Farah's keuze" />, 
                      document.querySelector('#farah'))
              </script>
          </body>
          
        3. Met dit als resultaat:
          marvel-class-encapsulation-reusability
          marvel-class-encapsulation-reusability

JI
2020-04-17 09:13:08